package com.xiaolin.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaolin.admin.constants.MenuTypeConstant;
import com.xiaolin.admin.exception.ServiceException;
import com.xiaolin.admin.mapper.SysMenuMapper;
import com.xiaolin.admin.mapper.SysRoleMenuMapper;
import com.xiaolin.admin.model.dto.CurrentUser;
import com.xiaolin.admin.model.dto.SysMenuTree;
import com.xiaolin.admin.model.entity.SysMenu;
import com.xiaolin.admin.model.entity.SysRoleMenu;
import com.xiaolin.admin.service.SysMenuService;
import com.xiaolin.admin.utils.ContextUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 模块表 服务实现类
 * </p>
 *
 * @author xiaolin
 * @since 2024-08-01
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    @Autowired
    private SysMenuMapper menuMapper;
    @Autowired
    private SysRoleMenuMapper roleMenuMapper;
    @Autowired
    private ContextUtil contextUtil;

    @Override
    public List<SysMenuTree> getMenuTree(SysMenu menu) {
        List<SysMenuTree> menuTrees = new ArrayList<>();
        List<SysMenu> menus = menuMapper.getMenuList(menu);
        if (!CollectionUtils.isEmpty(menus)) {
            List<Integer> allIds = menus.stream().map(SysMenu::getId).collect(Collectors.toList());
            for (SysMenu menuItem : menus) {
                // 找出第一层级的组织
                if (!allIds.contains(menuItem.getPid())) {
                    SysMenuTree menuTree = new SysMenuTree();
                    BeanUtils.copyProperties(menuItem, menuTree);
                    // 构建组织数
                    menuTree.setChildren(buildMenuTree(menus, menuItem.getId()));
                    menuTrees.add(menuTree);
                }
            }
        }
        return menuTrees;
    }

    private List<SysMenuTree> buildMenuTree(List<SysMenu> menus, Integer pid) {
        List<SysMenuTree> menuTrees = null;
        for (SysMenu menu : menus) {
            if (pid.equals(menu.getPid())) {
                if (CollectionUtils.isEmpty(menuTrees)) {
                    menuTrees = new ArrayList<>();
                }
                SysMenuTree menuTree = new SysMenuTree();
                BeanUtils.copyProperties(menu, menuTree);
                menuTree.setChildren(buildMenuTree(menus, menuTree.getId()));
                menuTrees.add(menuTree);
            }
        }
        return menuTrees;
    }

    /**
     * 校验菜单唯一性
     *
     * @param menu
     * @return
     */
    @Override
    public void checkUnique(SysMenu menu) {
        long count = menuMapper.selectCount(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getPid, menu.getPid())
                .eq(SysMenu::getMenuName, menu.getMenuName())
                .ne(Objects.nonNull(menu.getId()), SysMenu::getId, menu.getId()));
        if (count > 0) {
            ServiceException.error("兄弟菜单名称重复了");
        }
    }

    @Override
    public void checkMenuRelation(Integer menuId) {
        long count = menuMapper.selectCount(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getPid, menuId));
        if (count > 0) {
            ServiceException.error("该菜单有下属菜单，无法删除");
        }
    }

    @Override
    public void checkRoleRelation(Integer menuId) {
        long count = roleMenuMapper.selectCount(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, menuId));
        if (count > 0) {
            ServiceException.error("该菜单关联了角色，无法删除");
        }
    }


    @Override
    public boolean addMenu(SysMenu menu) {
        CurrentUser user = contextUtil.getCurrentUser();
        // 校验菜单唯一性
        checkUnique(menu);
        // 菜单数据过滤
        filterData(menu);
        menu.setCreator(user.getId());
        menu.setUpdator(user.getId());
        menuMapper.insert(menu);
        return true;
    }

    @Override
    public SysMenu getMenu(Integer id) {
        return menuMapper.selectById(id);
    }

    @Override
    public boolean updateMenu(SysMenu menu) {
        // 校验菜单唯一性
        checkUnique(menu);
        // 菜单数据过滤
        filterData(menu);
        menuMapper.updateById(menu);
        return true;
    }

    @Override
    public boolean status(Integer id, String status) {
        CurrentUser user = contextUtil.getCurrentUser();
        menuMapper.update(new SysMenu(), new UpdateWrapper<SysMenu>().lambda()
                .set(SysMenu::getAvailable, status)
                .set(SysMenu::getUpdator, user.getId())
                .eq(SysMenu::getId, id));
        return true;
    }

    /**
     * 菜单数据过滤
     *
     * @param menu
     */
    private void filterData(SysMenu menu) {
        switch (menu.getMenuType()) {
            case "1":
                menu.setPermission(null);
                break;
            case "2":
                break;
            case "3":
                menu.setIcon(null);
                menu.setRoutePath(null);
                menu.setComponentPath(null);
                break;
        }
    }

    @Override
    public boolean deleteMenu(Integer id) {
        // 校验菜单是否有子菜单
        checkMenuRelation(id);
        // 校验菜单与角色是否关联
        checkRoleRelation(id);
        menuMapper.deleteById(id);
        return true;
    }

    /**
     * 获取用户菜单权限
     *
     * @return
     */
    @Override
    public List<SysMenuTree> getUserMenuPermissions() {
        CurrentUser currentUser = contextUtil.getCurrentUser();
        List<SysMenu> menus = menuMapper.getUserMenuPermissions(currentUser.getId());
        // 过滤掉接口权限
        menus = menus.stream().filter(item -> !MenuTypeConstant.API.equals(item.getMenuType())).collect(Collectors.toList());
        List<SysMenuTree> menuTrees = buildMenuTree(menus, -1);
        return CollectionUtils.isEmpty(menuTrees) ? Collections.emptyList() : menuTrees;
    }

    /**
     * 获取用户接口权限
     *
     * @return
     */
    @Override
    public List<String> getUserApiPermissions() {
        CurrentUser currentUser = contextUtil.getCurrentUser();
        List<SysMenu> menus = menuMapper.getUserMenuPermissions(currentUser.getId());
        // 过滤出接口权限
        return menus.stream().filter(item -> !MenuTypeConstant.DIRECT.equals(item.getMenuType())).map(SysMenu::getPermission).collect(Collectors.toList());
    }
}
